package user.view;

import static org.math.array.DoubleArray.increment;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;

import javax.swing.BorderFactory;
import javax.swing.JOptionPane;
import javax.swing.Timer;
import javax.swing.border.Border;
import javax.swing.text.JTextComponent;

import model.doe.ElongFocusFocusator;
import model.util.FourerExecutor;
import model.util.FourerExecutor.DoeType;

import system.activity.MainListener;
import system.elements.ControlTextField;
import system.util.PlotBuilder;

public class ElongFocusFocusatorImpl extends Controls {

	private javax.swing.JLabel apertureRadiusLabel;
	private ControlTextField apertureRadiusText;
	private javax.swing.JButton cancelButton;
	private ControlTextField focalLengthText;
	private javax.swing.JLabel focalLengtnLabel;
	private javax.swing.JButton okButton;
	private javax.swing.JLabel focalDepthLabel;
	private ControlTextField focalDepthText;
	private javax.swing.JLabel stepLabel;
	private ControlTextField stepText;
	private javax.swing.JCheckBox withLens;
	private javax.swing.JLabel wlLabel;
	private ControlTextField wlText;
	private javax.swing.JCheckBox phase;
	private javax.swing.JCheckBox signPhase;
	private javax.swing.JCheckBox fourer;

	public ElongFocusFocusatorImpl(final MainListener listener) {
		this.listener = listener;
		this.setLayout(new java.awt.BorderLayout());

		init();
	}

	public ElongFocusFocusatorImpl(final MainListener listener,
			ArrayList<String> params) {
		this.listener = listener;
		this.setLayout(new java.awt.BorderLayout());
		initFromHistory(params);
	}

	@Override
	protected LinkedList<JTextComponent> elementsQueue() {
		LinkedList<JTextComponent> result = new LinkedList<JTextComponent>();
		result.add(apertureRadiusText);
		result.add(focalLengthText);
		result.add(focalDepthText);
		result.add(wlText);
		result.add(stepText);
		return result;
	}

	@Override
	protected void init() {
		apertureRadiusLabel = new javax.swing.JLabel();
		apertureRadiusText = new ControlTextField();
		focalLengtnLabel = new javax.swing.JLabel();
		focalLengthText = new ControlTextField();
		focalDepthText = new ControlTextField();
		wlText = new ControlTextField();
		focalDepthLabel = new javax.swing.JLabel();
		wlLabel = new javax.swing.JLabel();
		okButton = new javax.swing.JButton();
		cancelButton = new javax.swing.JButton();
		stepLabel = new javax.swing.JLabel();
		stepText = new ControlTextField();
		withLens = new javax.swing.JCheckBox();

		phase = new javax.swing.JCheckBox();
		signPhase = new javax.swing.JCheckBox();
		fourer = new javax.swing.JCheckBox();
		setName("Form"); // NOI18N

		apertureRadiusLabel.setText("Радиус апертуры"); // NOI18N
		apertureRadiusText.setText("6.4"); // NOI18N
		focalLengtnLabel.setText("Фокальное расстояние"); // NOI18N
		focalLengthText.setText("500"); // NOI18N
		focalDepthText.setText("500"); // NOI18N
		wlText.setText("10.6"); // NOI18N
		focalDepthLabel.setText("Величина отрезка"); // NOI18N
		wlLabel.setText("Длина волны (микрон)"); // NOI18N
		okButton.setText("Рассчитать"); // NOI18N
		cancelButton.setText("Закрыть"); // NOI18N
		stepLabel.setText("Шаг дескретизации"); // NOI18N
		stepText.setText("0.05"); // NOI18N
		withLens.setText("Рассчитать с линзой"); // NOI18N
		phase.setText("Расчет фазы");
		signPhase.setText("Расчет знака фазы");
		fourer.setText("Выполнить преобразование Фурье");

		fourer.setEnabled(false);
		phase.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				checkFourerAvailable();
			}

		});

		javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
		this.setLayout(layout);
		layout.setHorizontalGroup(layout
				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
				.addGroup(
						layout.createSequentialGroup()
								.addContainerGap()
								.addGroup(
										layout.createParallelGroup(
												javax.swing.GroupLayout.Alignment.LEADING)
												.addComponent(signPhase)
												.addComponent(phase)
												.addComponent(fourer)
												.addComponent(withLens)
												.addGroup(
														javax.swing.GroupLayout.Alignment.TRAILING,
														layout.createSequentialGroup()
																.addComponent(
																		okButton)
																.addPreferredGap(
																		javax.swing.LayoutStyle.ComponentPlacement.RELATED)
																.addComponent(
																		cancelButton))
												.addGroup(
														layout.createSequentialGroup()
																.addGroup(
																		layout.createParallelGroup(
																				javax.swing.GroupLayout.Alignment.TRAILING,
																				false)
																				.addComponent(
																						stepLabel,
																						javax.swing.GroupLayout.Alignment.LEADING,
																						javax.swing.GroupLayout.DEFAULT_SIZE,
																						javax.swing.GroupLayout.DEFAULT_SIZE,
																						Short.MAX_VALUE)
																				.addComponent(
																						apertureRadiusLabel,
																						javax.swing.GroupLayout.Alignment.LEADING,
																						javax.swing.GroupLayout.DEFAULT_SIZE,
																						148,
																						Short.MAX_VALUE)
																				.addComponent(
																						focalLengtnLabel,
																						javax.swing.GroupLayout.Alignment.LEADING,
																						javax.swing.GroupLayout.DEFAULT_SIZE,
																						javax.swing.GroupLayout.DEFAULT_SIZE,
																						Short.MAX_VALUE)
																				.addComponent(
																						focalDepthLabel,
																						javax.swing.GroupLayout.Alignment.LEADING,
																						javax.swing.GroupLayout.DEFAULT_SIZE,
																						javax.swing.GroupLayout.DEFAULT_SIZE,
																						Short.MAX_VALUE)
																				.addComponent(
																						wlLabel,
																						javax.swing.GroupLayout.Alignment.LEADING,
																						javax.swing.GroupLayout.DEFAULT_SIZE,
																						javax.swing.GroupLayout.DEFAULT_SIZE,
																						Short.MAX_VALUE))
																.addPreferredGap(
																		javax.swing.LayoutStyle.ComponentPlacement.RELATED)
																.addGroup(
																		layout.createParallelGroup(
																				javax.swing.GroupLayout.Alignment.LEADING)
																				.addComponent(
																						wlText,
																						javax.swing.GroupLayout.DEFAULT_SIZE,
																						113,
																						Short.MAX_VALUE)
																				.addComponent(
																						focalDepthText,
																						javax.swing.GroupLayout.DEFAULT_SIZE,
																						113,
																						Short.MAX_VALUE)
																				.addComponent(
																						focalLengthText,
																						javax.swing.GroupLayout.DEFAULT_SIZE,
																						113,
																						Short.MAX_VALUE)
																				.addComponent(
																						apertureRadiusText,
																						javax.swing.GroupLayout.DEFAULT_SIZE,
																						113,
																						Short.MAX_VALUE)
																				.addComponent(
																						stepText,
																						javax.swing.GroupLayout.DEFAULT_SIZE,
																						113,
																						Short.MAX_VALUE))))
								.addContainerGap()));
		layout.setVerticalGroup(layout
				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
				.addGroup(
						layout.createSequentialGroup()
								.addContainerGap()
								.addGroup(
										layout.createParallelGroup(
												javax.swing.GroupLayout.Alignment.BASELINE)
												.addComponent(
														apertureRadiusLabel)
												.addComponent(
														apertureRadiusText,
														javax.swing.GroupLayout.PREFERRED_SIZE,
														javax.swing.GroupLayout.DEFAULT_SIZE,
														javax.swing.GroupLayout.PREFERRED_SIZE))
								.addGap(18, 18, 18)
								.addGroup(
										layout.createParallelGroup(
												javax.swing.GroupLayout.Alignment.BASELINE)
												.addComponent(focalLengtnLabel)
												.addComponent(
														focalLengthText,
														javax.swing.GroupLayout.PREFERRED_SIZE,
														javax.swing.GroupLayout.DEFAULT_SIZE,
														javax.swing.GroupLayout.PREFERRED_SIZE))
								.addGap(18, 18, 18)
								.addGroup(
										layout.createParallelGroup(
												javax.swing.GroupLayout.Alignment.BASELINE)
												.addComponent(focalDepthLabel)
												.addComponent(
														focalDepthText,
														javax.swing.GroupLayout.PREFERRED_SIZE,
														javax.swing.GroupLayout.DEFAULT_SIZE,
														javax.swing.GroupLayout.PREFERRED_SIZE))
								.addGap(18, 18, 18)
								.addGroup(
										layout.createParallelGroup(
												javax.swing.GroupLayout.Alignment.BASELINE)
												.addComponent(wlLabel)
												.addComponent(
														wlText,
														javax.swing.GroupLayout.PREFERRED_SIZE,
														javax.swing.GroupLayout.DEFAULT_SIZE,
														javax.swing.GroupLayout.PREFERRED_SIZE))
								.addGap(18, 18, 18)
								.addGroup(
										layout.createParallelGroup(
												javax.swing.GroupLayout.Alignment.BASELINE)
												.addComponent(stepLabel)
												.addComponent(
														stepText,
														javax.swing.GroupLayout.PREFERRED_SIZE,
														javax.swing.GroupLayout.DEFAULT_SIZE,
														javax.swing.GroupLayout.PREFERRED_SIZE))
								.addGap(16, 16, 16)
								.addComponent(withLens)
								.addPreferredGap(
										javax.swing.LayoutStyle.ComponentPlacement.RELATED)
								.addComponent(phase)
								.addPreferredGap(
										javax.swing.LayoutStyle.ComponentPlacement.RELATED)
								.addComponent(signPhase)
								.addPreferredGap(
										javax.swing.LayoutStyle.ComponentPlacement.RELATED)
								.addComponent(fourer)
								.addPreferredGap(
										javax.swing.LayoutStyle.ComponentPlacement.RELATED,
										67, Short.MAX_VALUE)
								.addGroup(
										layout.createParallelGroup(
												javax.swing.GroupLayout.Alignment.BASELINE)
												.addComponent(okButton)
												.addComponent(cancelButton))
								.addContainerGap()));
		okButton.addMouseListener(new java.awt.event.MouseAdapter() {
			public void mouseClicked(java.awt.event.MouseEvent evt) {
				try {
					okButton.setEnabled(false);
					final ElongFocusFocusator focusator = new ElongFocusFocusator(
							Double.parseDouble(apertureRadiusText.getText()),
							Double.parseDouble(focalLengthText.getText()),
							Double.parseDouble(wlText.getText()), Double
									.parseDouble(focalDepthText.getText()),
							Double.parseDouble(stepText.getText()), withLens
									.isSelected());
					listener.clearImagePanel();
					listener.setLoadStatus();
					java.awt.event.ActionListener actionListener = new java.awt.event.ActionListener() {
						public void actionPerformed(
								java.awt.event.ActionEvent actionEvent) {
							try {
								if (phase.isSelected()) {
									listener.addImagePanel(focusator
											.getPhaseTo2PiMImage(),
											"Распределение фазы");
								}
								if (signPhase.isSelected()) {
									listener.addImagePanel(
											focusator.getSignPhaseImage(),
											"Распределение знака фазы");
								}
								if (phase.isSelected() && fourer.isSelected()) {
									FourerExecutor fourer = new FourerExecutor();
									ArrayList<BufferedImage> fourerImages = fourer
											.fft(focusator, DoeType.PHASE);
									listener.addImagePanel(fourerImages.get(0),
											"Распредление амплитуды после преобразования Фурье");
									
									double[][] z = fourer.getResultAmpl();
									double[] x = increment(0d, 1d, z[0].length);
									double[] y = increment(0d, 1d, z.length);
									String plotDescription = "Распределение амплитуды после преобразования Фурье - график";
									listener.addFastPlotPanel(PlotBuilder.buildFast3DPlot(x, y, z, plotDescription), "Распределение амплитуды после преобразования Фурье - график");
									
									
									
									listener.addImagePanel(fourerImages.get(1),
											"Распредление фазы после преобразования Фурье");
									onResize();
									listener.needRepaint();
								}
								onResize();
								listener.needRepaint();
								listener.removeLoadStatus();
								okButton.setEnabled(true);
							} catch (OutOfMemoryError ex) {
								listener.removeLoadStatus();
								okButton.setEnabled(true);
								listener.showErrorMessage("Переполнение памяти");
							} catch (IllegalArgumentException ex) {
								listener.removeLoadStatus();
								okButton.setEnabled(true);
								listener.showErrorMessage(ex.getMessage());
							}
						}
					};
					Timer timer = new Timer(500, actionListener);
					timer.setRepeats(false);
					timer.start();
				} catch (NumberFormatException ex) {
					listener.showErrorMessage("Ошибка формата входных данных");
					listener.removeLoadStatus();
					okButton.setEnabled(true);
				}
			}
		});
		cancelButton.addMouseListener(new java.awt.event.MouseAdapter() {
			public void mouseClicked(java.awt.event.MouseEvent evt) {
				listener.removeLeftPanel();
				onResize();
				listener.needRepaint();
			}
		});
		Border border = BorderFactory.createEtchedBorder(Color.white,
				new Color(178, 178, 178));
		this.setBorder(border);
		listener.addPanel(this);
		this.show();
	}

	void onResize() {
		this.show();
	}

	@Override
	public void setListener(MainListener listener) {
		this.listener = listener;
	}

	@Override
	public Collection<String> getControlsValues() {
		Date date = new Date();
		Collection<String> result = new ArrayList<String>();
		result.add("                                                                                 "
				+ date.getHours()
				+ ":"
				+ date.getMinutes()
				+ ":"
				+ date.getSeconds()
				+ "   "
				+ date.getDate()
				+ "."
				+ (date.getMonth() + 1) + "." + (date.getYear() + 1900));
		result.add("Elong focus focusator");
		result.add("Введенные параметры:");
		result.add(apertureRadiusLabel.getText() + " = "
				+ apertureRadiusText.getText());
		result.add(focalLengtnLabel.getText() + " = "
				+ focalLengthText.getText());
		result.add(focalDepthLabel.getText() + " = " + focalDepthText.getText());
		result.add(wlLabel.getText() + " = " + wlText.getText());
		result.add(stepLabel.getText() + " = " + stepText.getText());
		result.add(withLens.isSelected() ? "Расчет проводился с линзой"
				: "Расчет проводился без линзы");
		result.add("");
		return result;
	}

	@Override
	String getClassName() {
		return this.getClass().getCanonicalName();
	}

	private void checkFourerAvailable() {
		fourer.setEnabled(phase.isSelected());
		if (fourer.isEnabled() == false) {
			fourer.setSelected(false);
		}
	}
}
